#include <IO/Keyboard.h>
#include <Memory/Heap.h>
#include <Kernel/GlobalData.h>
#include <Utility/intrinsic.h>

#define SC_ESC (0x01)
#define SC_LCTRL (0x1D)
#define SC_RCTRL (0xE01D)
#define SC_LALT (0x38)
#define SC_RALT (0xE038)
#define SC_LSHIFT (0x2A)
#define SC_RSHIFT (0x36)
#define SC_CAPSLOCK (0x3A)
#define SC_F1 (0x3B)
#define SC_F2 (0x3C)
#define SC_F3 (0x3D)
#define SC_F4 (0x3E)
#define SC_F5 (0x3F)
#define SC_F6 (0x40)
#define SC_F7 (0x41)
#define SC_F8 (0x42)
#define SC_F9 (0x43)
#define SC_F10 (0x44)
#define SC_F11 (0x57)
#define SC_F12 (0x58)

static char keymap[][2] = {
    [0x00] = {'\0', '\0'}, /* NUL */
    [0x29] = {'`', '~'},
    [0x02] = {'1', '!'},
    [0x03] = {'2', '@'},
    [0x04] = {'3', '#'},
    [0x05] = {'4', '$'},
    [0x06] = {'5', '%'},
    [0x07] = {'6', '^'},
    [0x08] = {'7', '&'},
    [0x09] = {'8', '*'},
    [0x0A] = {'9', '('},
    [0x0B] = {'0', ')'},
    [0x0C] = {'-', '_'},
    [0x0D] = {'=', '+'},
    [0x0E] = {'\b', '\b'},
    [0x0F] = {'\t', '\t'},
    [0x10] = {'q', 'Q'},
    [0x11] = {'w', 'W'},
    [0x12] = {'e', 'E'},
    [0x13] = {'r', 'R'},
    [0x14] = {'t', 'T'},
    [0x15] = {'y', 'Y'},
    [0x16] = {'u', 'U'},
    [0x17] = {'i', 'I'},
    [0x18] = {'o', 'O'},
    [0x19] = {'p', 'P'},
    [0x1A] = {'[', '{'},
    [0x1B] = {']', '}'},
    [0x2B] = {'\\', '|'},
    [0x1E] = {'a', 'A'},
    [0x1F] = {'s', 'S'},
    [0x20] = {'d', 'D'},
    [0x21] = {'f', 'F'},
    [0x22] = {'g', 'G'},
    [0x23] = {'h', 'H'},
    [0x24] = {'j', 'J'},
    [0x25] = {'k', 'K'},
    [0x26] = {'l', 'L'},
    [0x27] = {';', ':'},
    [0x28] = {'\'', '\"'},
    [0x1C] = {'\r', '\r'},
    [0x2C] = {'z', 'Z'},
    [0x2D] = {'x', 'X'},
    [0x2E] = {'c', 'C'},
    [0x2F] = {'v', 'V'},
    [0x30] = {'b', 'B'},
    [0x31] = {'n', 'N'},
    [0x32] = {'m', 'M'},
    [0x33] = {',', '<'},
    [0x34] = {'.', '>'},
    [0x35] = {'/', '?'},
    [0x39] = {' ', ' '},
};

LPKeyboardInputBuffer CreateKeyboardInputBuffer(DWORD dwBufferSize)
{
    LPKeyboardInputBuffer lpRet = HeapAllocate(g_lpKernelHeap, HEAP_ZERO_MEMORY, sizeof(KeyboardInputBuffer));
    if (!lpRet) return NULL;
    lpRet->dwBufferSize = dwBufferSize;
    lpRet->lpBuffer = HeapAllocate(g_lpKernelHeap, 0, dwBufferSize); /* 缓冲区无需 0 初始化 */
    if (!lpRet->lpBuffer) /* 缓冲区创建失败 */
    {
        HeapFree(g_lpKernelHeap, lpRet);
        return NULL;
    }
    return lpRet;
}

void DestroyKeyboardInputBuffer(LPKeyboardInputBuffer lpKeyboardInputBuffer)
{
    HeapFree(g_lpKernelHeap, lpKeyboardInputBuffer->lpBuffer);
    HeapFree(g_lpKernelHeap, lpKeyboardInputBuffer);
}

void AppendCharToKeyboardInputBuffer(LPKeyboardInputBuffer lpKeyboardInputBuffer)
{
    static QWORD qwScanCode;
    static BOOL bExt = FALSE;
    static BOOL blctrl = FALSE;
    static BOOL brctrl = FALSE;
    static BOOL blshift = FALSE;
    static BOOL brshift = FALSE;
    static BOOL blalt = FALSE;
    static BOOL bralt = FALSE;
    static BOOL bcapslock = FALSE;
#ifdef _8042_
    BYTE bPartialScanCode = IN_BYTE(KEYBOARD_INPUT_PORT);
    if (bExt)
    {
        qwScanCode <<= 8;
        qwScanCode |= bPartialScanCode;
        bExt = FALSE;
    }
    else
    {
        qwScanCode = bPartialScanCode;
    }
    if (bPartialScanCode == 0xe0) /* 0xe0 为扩展扫描码 */
    {
        qwScanCode = 0xe0;
        bExt = TRUE;
        return;
    }
#endif
    CHAR c;
    if ((lpKeyboardInputBuffer->dwRear + 1) % lpKeyboardInputBuffer->dwBufferSize == lpKeyboardInputBuffer->dwFront) /* 缓冲区满时不再向其中添加新元素 */
    {
        return;
    }
    BOOL bBreak = (BOOL)(0x80 & qwScanCode); /* 第 7 位代表通断 */
    BOOL bCapital = FALSE;
    BOOL bEscape = blctrl || brctrl || blalt || bralt; /* 是否转义 */
    if (bBreak) /* 断码 */
    {
        if ((qwScanCode & ~0x80) == SC_LALT) 
        {
            blalt = FALSE;
        }
        else if ((qwScanCode & ~0x80) == SC_RALT)
        {
            bralt = FALSE;
        }
        else if ((qwScanCode & ~0x80) == SC_LCTRL)
        {
            blctrl = FALSE;
        }
        else if ((qwScanCode & ~0x80) == SC_RCTRL)
        {
            brctrl = FALSE;
        }
        else if ((qwScanCode & ~0x80) == SC_LSHIFT)
        {
            blshift = FALSE;
        }
        else if ((qwScanCode & ~0x80) == SC_RSHIFT)
        {
            blshift = FALSE;
        }
        return;
    }
    else /* 通码 */
    {
        if (qwScanCode == SC_LALT) 
        {
            blalt = TRUE;
        }
        else if (qwScanCode == SC_RALT)
        {
            bralt = TRUE;
        }
        else if (qwScanCode == SC_LCTRL)
        {
            blctrl = TRUE;
        }
        else if (qwScanCode == SC_RCTRL)
        {
            brctrl = TRUE;
        }
        else if (qwScanCode == SC_CAPSLOCK)
        {
            bcapslock = !bcapslock; /* CAPSLOCK 状态取反 */
        }
        else if (qwScanCode == SC_LSHIFT)
        {
            blshift = TRUE;
        }
        else if (qwScanCode == SC_RSHIFT)
        {
            blshift = TRUE;
        }
        else if (qwScanCode < sizeof(keymap) / sizeof(keymap[0]) && !bEscape)
        {
            goto printable;
        }
        return;
    }
printable:
    bCapital = (blshift || brshift) ^ bcapslock; /* 判定是否需要大写 */
    if (bCapital) bCapital = 1;
    else bCapital = 0;
    c = keymap[(qwScanCode & ~0x80)][bCapital];
    if (c) /* 非 '\0' 字符 */
    {
        *(lpKeyboardInputBuffer->lpBuffer + lpKeyboardInputBuffer->dwRear) = c;
        lpKeyboardInputBuffer->dwRear = (lpKeyboardInputBuffer->dwRear + 1) % lpKeyboardInputBuffer->dwBufferSize;
    }
    return;
}

CHAR RetrieveCharFromKeyboardInputBuffer(LPKeyboardInputBuffer lpKeyboardInputBuffer)
{
    if (IsKeyboardInputBufferEmpty(lpKeyboardInputBuffer))
    {
        return '\0';
    }
    CHAR bRet = *(lpKeyboardInputBuffer->lpBuffer + lpKeyboardInputBuffer->dwFront);
    lpKeyboardInputBuffer->dwFront = (lpKeyboardInputBuffer->dwFront + 1) % lpKeyboardInputBuffer->dwBufferSize;
    return bRet;
}